class MVVM {
  constructor(el, data) {
    this.el = document.querySelector(el);
    this._data = data;
    // this.data = data;

    // 存储当前的 Dom 节点
    this.domPool = {};
    this.init();
  }
  init() {
    this.initData();
    this.initDom();
    this.proxy(this._data);
  }
  initDom() {
    this.bindDom(this.el);
    this.bindInput(this.el);
    console.log(this.domPool);
  }
  initData() {
    const _this = this;

    // ES5 数据劫持 Vue2
    this.data = {}; // 这个对象是为了 在页面展示时 进行判断展示的对象
    for (let key in this._data) {
      // 数据劫持(代理)
      Object.defineProperty(this.data, key, {
        get() {
          // 拿取 this.data 数据时 返回的时 this._data 的值
          return _this._data[key];
        },
        set(newVal) {
          console.log("设置数据", key, newVal);
          // 进行修改这个值的时候,let 作用域给每一个 key 保存了一个作用域 拿到当前作用域中的 key 也就是当前 <span></span> 这个标签 修改掉了当前标签中的值
          _this.domPool[key].innerHTML = newVal;
          // 将 data 中的数据进行同步更新
          _this._data[key] = newVal;
        },
      });
    }
    // ES6 数据劫持 Vue3
    // this.data = new Proxy(this.data, {
    //   // 拿到目标对象的 key 值
    //   get(target, key) {
    //     return Reflect.get(target, key);
    //   },
    //   // 第一个参数 是目标对象
    //   // 第二个参数 是当前的 key 键名
    //   // 第三个参数 是当前的 key 值
    //   set(target, key, value) {
    //     _this.domPool[key].innerHTML = value;
    //     // 将 value 修改 目标对象的 key
    //     return Reflect.set(target, key, value);
    //   },
    // });
  }
  // 将 this._data 中的所有属性全部放置在 this 实例对象上 app.name 的调用方式
  proxy(target) {
    Object.keys(target).forEach((prop) => {
      Object.defineProperty(this, prop, {
        configurable: true,
        enumerable: true,
        get() {
          return target[prop];
        },
        set(newValue) {
          target[props] = newValue;
        },
      });
    });
  }
  bindDom(el) {
    const childNodes = el.childNodes;
    childNodes.forEach((item) => {
      //   nodeType === 3 表示当前节点里面是文本
      if (item.nodeType == 3) {
        // console.log("text", item);

        const _value = item.nodeValue;
        if (_value.trim().length) {
          let _isValid = /\{\{(.+?)\}\}/.test(_value);
          if (_isValid) {
            // console.log(item.nodeValue);   //节点

            // 拿到对应的 key
            let _key = _value.match(/\{\{(.+?)\}\}/)[1].trim();
            // 获取到当前子节点的父节点 也就是当前环境中的 <span></span> 标签 存储到domPool 对象当中
            this.domPool[_key] = item.parentNode;
            item.parentNode.innerText = this.data[_key] || "请输入";
          }
        }
      }

      item.childNodes && this.bindDom(item);
    });
  }
  bindInput(el) {
    const _allInputs = el.querySelectorAll("input");
    _allInputs.forEach((input) => {
      // 取自定义的属性
      const _vModel = input.getAttribute("v-model");
      if (_vModel) {
        input.addEventListener("keyup", this.handleInput.bind(this, _vModel, input, false));
      }
    });
  }
  //   绑定事件处理函数,并且处理数据
  handleInput(key, input) {
    const _value = input.value;
    this.data[key] = _value;
    console.log(this);
  }
  setData(key, value) {
    this.data[key] = value;
  }
}

/*
    1.将数据转成响应时数据 Object.defineProerty Proxy
    2.input -> input/keyup -> 事件处理函数得到绑定 -> 改变数据
    3.相关DOM -> 数据 -> 绑定
        操作数据的某一个属性-> 对应 DOM 改变
*/
